#!/usr/bin/env python
# -*- coding: utf-8 -*-
#

import os,os.path,tempfile,time

from bisect import insort

from bsddb import db,dbtables

try:
    import cPickle
    pickle = cPickle
except ImportError:
    import pickle

try :
    from hashlib import md5 as MD5
except :
    from md5 import md5 as MD5

PATH = os.sep.join((tempfile.gettempdir(), 'dbtables/hello'))

TABLE = 'hellotbl'

def logging(fmt, *args) : print fmt % args


class   TestDBTables_1(object) :
    def setUp(self) :
        logging('%s setUp', self.__class__.__name__)

        if os.path.exists(PATH) :
           self.removedirs(PATH)

        os.makedirs(PATH, 0777)

        self.tdb = dbtables.bsdTableDB(filename='tabletest.db', dbhome=PATH, create=1)

        ## setUp()

    def tearDown(self) :
        logging('%s tearDown', self.__class__.__name__)
        self.tdb.close()
        ## tearDown()

    def removedirs(self, path) :
        items = os.listdir(path)
        for name in items :
            fullpath = os.sep.join((path, name))
            if os.path.isdir(fullpath) :
                self.removedirs(fullpath)
            else :
                os.remove(fullpath)

        os.rmdir(path)
        ## removedirs


    def run(self) :
        logging('%s run', self.__class__.__name__)

        for test_func in (self.test01_simple, self.test02_tps, self.test03_tps) :
            self.setUp()
            try :
                test_func()
            finally :
                self.tearDown()

        ## run()

    ###################################################################

    def test01_simple(self) :
        table_name = 'location'
        cols = ['key','ts','op','fileno','offset','length']

        try :
            self.tdb.Drop(table_name)
        except dbtables.TableDBError :
            pass

        #self.tdb._db_print()
        self.tdb.CreateTable(table_name, cols)
        #self.tdb._db_print()

        self.tdb.Insert(table_name, 
                        {   'key' : 'hello', 
                            'ts'  : pickle.dumps(12345678, 1),
                            'op'  : pickle.dumps(0, 1),
                            'fileno' : pickle.dumps(0, 1),
                            'offset' : pickle.dumps(0, 1),
                            'length' : pickle.dumps(5, 1),
                        })
        self.tdb.Insert(table_name, 
                        {   'key' : 'world', 
                            'ts'  : pickle.dumps(12345679, 1),
                            'op'  : pickle.dumps(0, 1),
                            'fileno' : pickle.dumps(1, 1),
                            'offset' : pickle.dumps(6, 1),
                            'length' : pickle.dumps(5, 1),
                        })
        #self.tdb._db_print()

        values = self.tdb.Select(table_name, None, conditions={'key':None})
        #logging('%s', values)
        assert len(values) == 2

        values = self.tdb.Select(table_name, None, conditions={'key': lambda x : x =='hello'})
        #logging('%s', values)
        assert len(values) == 1

        values = self.tdb.Select(table_name, None, conditions={'key': dbtables.ExactCond('hello')})
        #logging('%s', values)
        assert len(values) == 1

        values = self.tdb.Select(table_name, ['key','ts','op'], conditions={'key': lambda x : x =='hello'})
        #logging('%s', values)
        assert len(values) == 1

        # test delete
        self.tdb.Delete(table_name, conditions={'fileno': lambda x : pickle.loads(x) == 0 })
        values = self.tdb.Select(table_name, ['key','ts','op'], conditions={'key': lambda x : x =='hello'})
        #logging('%s', values)
        assert len(values) == 0

        values = self.tdb.Select(table_name, ['key','ts','op','fileno'], conditions={'key': dbtables.ExactCond('world')})
        #logging('%s', values)
        assert len(values) == 1
        for v in values :
            assert v['fileno'] != 0

        ## test01_simple()


    def test02_tps(self) :
        table_name = 'location'
        cols = ['key','ts','op','fileno','offset','length']

        try :
            self.tdb.Drop(table_name)
        except dbtables.TableDBError :
            pass

        logging('test performance ...')

        #self.tdb._db_print()
        self.tdb.CreateTable(table_name, cols)
        #self.tdb._db_print()

        fileno = 0

        timestamp = int(time.time() * 1000)
        offset = 0
        length = 11

        time_start = time.time()
        times = 10000
        for x in xrange(times) :
            key = MD5(str(x)).hexdigest()
            timestamp += 1
            offset += length
            length += 11 + x
            self.tdb.Insert(table_name, 
                            {   'key' : key, 
                                'ts'  : pickle.dumps(timestamp, 1),
                                'op'  : pickle.dumps(0, 1),
                                'fileno' : pickle.dumps(fileno, 1),
                                'offset' : pickle.dumps(offset, 1),
                                'length' : pickle.dumps(length, 1),
                            })
            if x > 0 and (0 == (x % 1000)) :
                time_last = time.time() - time_start
                logging(' - test %d times last %.2f seconds ...', x, time_last)
                
        time_last = time.time() - time_start
        tps = times / time_last
        logging('test %d times last %.2f seconds, tps=%.2f', times, time_last, tps)
        ## test02_tps()


    def test03_tps(self) :
        table_name = 'location'
        cols = ['key','ts','op','fileno','offset','length']

        try :
            self.tdb.Drop(table_name)
        except dbtables.TableDBError :
            pass

        logging('test performance ...')

        #self.tdb._db_print()
        self.tdb.CreateTable(table_name, cols)
        #self.tdb._db_print()

        fileno = 0

        timestamp = int(time.time() * 1000)
        offset = 0
        length = 11

        records = []

        time_start = time.time()
        times = 10000
        for x in xrange(times) :
            key = MD5(str(x)).hexdigest()
            timestamp += 1
            offset += length
            length += 11 + x
            insort(records, (key,timestamp,0,fileno,offset,length))

        x = 0
        for key,timestamp,op,fileno,offset,length in records :    
            self.tdb.Insert(table_name, 
                            {   'key' : key, 
                                'ts'  : pickle.dumps(timestamp, 1),
                                'op'  : pickle.dumps(0, 1),
                                'fileno' : pickle.dumps(fileno, 1),
                                'offset' : pickle.dumps(offset, 1),
                                'length' : pickle.dumps(length, 1),
                            })
            x += 1
            if (0 == (x % 1000)) :
                time_last = time.time() - time_start
                logging(' - test %d times last %.2f seconds ...', x, time_last)
                
        records = []
        time_last = time.time() - time_start
        tps = times / time_last
        logging('test %d times last %.2f seconds, tps=%.2f', times, time_last, tps)
        ## test03_tps()

    ## class TestDBTables_1


if  __name__ == '__main__' :
    t = TestDBTables_1()

    t.run()


